require 'digest/sha1'

class User < ActiveRecord::Base
  has_one :core, :as => :resource
  include Authentication
  include Authentication::ByPassword
  include Authentication::ByCookieToken
  include Authorization::StatefulRoles
  
  belongs_to :location
  accepts_nested_attributes_for :location
  

  has_many :chat_messages
  has_many :forum_messages
  has_many :forum_topics
  has_many :passages
  has_many :insertions
  has_many :histories
  has_many :mails
  has_many :multimedias_created, :class_name => 'Multimedia'  
  has_many :cores
  has_many :votes  
  has_many :albums
  has_many :bugs
  
  has_and_belongs_to_many :bookmarks, :class_name => "Core", 
      :foreign_key => 'user_id', :association_foreign_key => 'core_id'
  
  validates_length_of       :name,    :within => 2..40 ,    :if => Proc.new { |user| !user.name.blank? }

  validates_presence_of     :email 
  validates_uniqueness_of   :email,    :if => Proc.new { |user| !user.email.blank? } 
  
  validates_each :email do |record, attr|
  	record.errors.add attr,
      record.errors.generate_message(attr, 'double_hash_mail' ) if (u = User.find_by_email_hash(Facebooker::User.hash_email(record.email)) and Facebooker::User.hash_email(record.email) != record.email_hash) 
  end

  default_value_for         :is_admin, false
  default_value_for         :notify_public_messages, true
  default_value_for         :notify_private_messages, true
  default_value_for         :notify_bookmark_events, true
  default_value_for         :max_distance, 50
  default_value_for         :colors, "28004D"
  default_value_for         :back_img, "0img.gif"
  
  validates_presence_of     :location, :back_img


  has_attached_file :banner,         
                    :default_url =>"",
                    :url  => "/images/banners/:id.:extension",
                    :path => ":rails_root/public/images/banners/:id.:extension",
                    :styles => {:original=>'580x100>'},
                    :convert_options => {  
                     :original => "-strip -quality 75"  
                    }
                    
  validates_attachment_content_type :banner,
    :content_type => ['image/jpg', 'image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png'],
    :message => I18n.t("photo.only_images")

  validates_attachment_size :banner,
    :less_than => 4.megabyte,
    :message => I18n.t("photo.max_size")

  
  
  
  attr_accessible :login, :email, :name, :password, :password_confirmation, :colors, :back_img, :alias,
                  :max_distance, :sites, :location, :location_attributes, :multimedias, 
                  :photos_attributes, :banner, :site, :image_id, :multimedias_created, :image

  before_validation {| record | record.login = record.email }
  
  
  after_create { | record |
     if record.image       
        record.image.user_id = record.id        
        record.image.save
        
        record.multimedias << record.image
                
     end     
     record.register_user_to_fb 
  }
  
  def self.after_create_set(rec, validation)
    
  end


  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  #
  # uff.  this is really an authorization, not authentication routine.  
  # We really need a Dispatch Chain here or something.
  # This will also let us return a human error message.
  #
  def self.authenticate(login, password)
    return nil if (login.blank? || password.blank?)
    u = find_in_state :first, :active, :conditions => {:login => login.downcase} # need to get the salt
    u && u.authenticated?(password) ? u : nil
  end

  def login=(value)
    write_attribute :login, (value ? value.downcase : nil)
  end

  def email=(value)
    write_attribute :email, (value ? value.downcase : nil)
  end
  
  def photos_attributes=(attributes)
    photo = TempPhoto.new(attributes)
    if photo.data_file_name || !attributes[:data_url].blank?        
      self.image = photo      
      unless self.new_record?
          photo.user_id = self.id
         self.multimedias << photo
      end
    end
  end
  

  def forgot_password
    @forgotten_password = true
    self.make_password_reset_code
  end

  def reset_password
    # First update the password_reset_code before setting the 
    # reset_password flag to avoid duplicate email notifications.
    update_attributes(:password_reset_code => nil)
    @reset_password = true
  end  

  #used in user_observer
  def recently_forgot_password?
    @forgotten_password
  end
  
  def recently_reset_password?
    @reset_password
  end
  
  def recently_activated?
    @recent_active
  end

  def import_fb_profile profile
    if profile.profile_url      
      self.name = profile.profile_url[profile.profile_url.rindex("/") + 1,profile.profile_url.length - 1] 
    else
      self.name = profile.name
    end
    self.location.full_address = profile.current_location.city.to_s + ", " + profile.current_location.state.to_s + 
                                    ", " + profile.current_location.country.to_s if (profile.current_location)
    self.photo.data_url = profile.pic_big if profile.pic_big
  end

  def must_have_kinds
  end 

  def images_view
    a = []
    a << { :big => get_avatar(:thumb_big), :original => get_avatar(:original) }  
    return a
  end
  
  def location_attributes
    @location
  end
  
  def location_attributes=(attributes)
    self.location = Location.set_location(attributes)
  end

  
  #find the user in the database, first by the facebook user id and if that fails through the email hash
  def self.find_by_fb_user(fb_user)
    User.find_by_fb_user_id(fb_user.uid) || User.find_by_email_hash(fb_user.email_hashes)
  end

  #Take the data returned from facebook and create a new user from it.
  #We don't get the email from Facebook and because a facebooker can only login through Connect we just generate a unique login name for them.
  #If you were using username to display to people you might want to get them to select one after registering through Facebook Connect
  def self.create_from_fb_connect(fb_user)
    if (user = find_by_fb_user(fb_user))
      user.fb_user_id = fb_user.uid.to_i  
      import_fb_profile
      user.save
    else
      city = fb_user.current_location ? fb_user.current_location.city + " " + fb_user.current_location.state + 
              " " + fb_user.current_location.country : "Roma Italia"      
      new_facebooker = User.new(:name => fb_user.name + 
                    (find(:first, :conditions => ["name like ?", fb_user.name]) ? 
                        "_" + rand(300000).to_s : ""), :login => (-30000 - rand(3000000)).to_s , 
       :password => "", :email => "", 
       :location => Location.set_location( {:full_address => city }),
        :photos_attributes => {:data_url => fb_user.pic_big})
      
      new_facebooker.fb_user_id = fb_user.uid.to_i
      new_facebooker.generate_alias
      new_facebooker.email_hash = fb_user.email_hashes[0]      
      #We need to save without validations       
      new_facebooker.save(false)             
      new_facebooker.image_id = new_facebooker.image.id
      new_facebooker.save(false)   
    end
  end
  
  #We are going to connect this user object with a facebook id. But only ever one account.
  def link_fb_connect(fb_user_id)
    unless fb_user_id.nil?
      #check for existing account
      existing_fb_user = User.find_by_fb_user_id(fb_user_id)
      #unlink the existing account
      unless existing_fb_user.nil?
        existing_fb_user.fb_user_id = nil
        existing_fb_user.save(false)
      end
      #link the new one
      self.fb_user_id = fb_user_id
      save(false)
    end
  end
  
  #The Facebook registers user method is going to send the users email hash and our account id to Facebook
  #We need this so Facebook can find friends on our local application even if they have not connect through connect
  #We hen use the email hash in the database to later identify a user from Facebook with a local user
  def register_user_to_fb
    users = {:email => email, :account_id => id}
    Facebooker::User.register([users])    
    unless (email.blank?)
     self.email_hash = Facebooker::User.hash_email(email)    
      save(false)
    end
  end

  def facebook_user?
    return !fb_user_id.nil? && fb_user_id > 0
  end
  

  protected
    
    def make_activation_code
        self.deleted_at = nil
        self.activation_code = self.class.make_token
    end

    def make_password_reset_code
      self.password_reset_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
    end

end
